package com.yupi.yupicturebackend.aop;

import com.yupi.yupicturebackend.annotation.AuthCheck;
import com.yupi.yupicturebackend.exception.BusinessException;
import com.yupi.yupicturebackend.exception.ErrorCode;
import com.yupi.yupicturebackend.model.entity.User;
import com.yupi.yupicturebackend.model.enums.UserRoleEnum;
import com.yupi.yupicturebackend.service.UserService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

@Aspect
@Component
public class AuthInterceptor {

    @Resource
    private UserService userService;

    /**
     * 公共API方法：AOP权限拦截入口
     *
     * @param joinPoint 切入点
     * @param authCheck 权限校验注解
     * @return 方法执行结果
     * @throws Throwable 权限不足或系统异常
     */
    @Around("@annotation(authCheck)")
    public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
        String mustRole = authCheck.mustRole();
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        // 获取当前登录用户
        User loginUser = userService.getLoginUser(request);
        // 权限校验，未通过会抛出详细异常
        validateAuth(loginUser, mustRole);
        // 通过权限校验，放行
        return joinPoint.proceed();
    }

    // ===================== 私有辅助方法 =====================

    /**
     * 权限校验方法，统一命名validateAuth，便于全局检索和维护
     * <p>使用Optional、函数式接口等现代Java特性，减少嵌套和重复代码。</p>
     *
     * @param loginUser 当前登录用户
     * @param mustRole  必须具备的角色
     */
    private void validateAuth(User loginUser, String mustRole) {
        // 1. 获取注解要求的角色枚举
        UserRoleEnum mustRoleEnum = Optional.ofNullable(mustRole)
                .map(UserRoleEnum::getEnumByValue)
                .orElse(null);
        // 2. 如果不需要权限，直接放行
        if (mustRoleEnum == null) {
            return;
        }
        // 3. 获取当前用户角色枚举
        UserRoleEnum userRoleEnum = Optional.ofNullable(loginUser)
                .map(User::getUserRole)
                .map(UserRoleEnum::getEnumByValue)
                .orElse(null);
        // 4. 用户未登录或角色无效，抛详细异常
        if (userRoleEnum == null) {
            throw new BusinessException(
                    ErrorCode.NO_AUTH_ERROR,
                    "用户未登录或角色无效，当前用户信息：" + (loginUser == null ? "null" : loginUser.toString())
            );
        }
        // 5. 要求管理员权限但用户不是管理员，抛详细异常
        if (UserRoleEnum.ADMIN.equals(mustRoleEnum) && !UserRoleEnum.ADMIN.equals(userRoleEnum)) {
            throw new BusinessException(
                    ErrorCode.NO_AUTH_ERROR,
                    "需要管理员权限，当前用户角色：" + userRoleEnum.getText()
            );
        }
        // 6. 其他角色校验可在此扩展
        // ...
    }
}
